﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using DogDemo.Common;

namespace DogDemo
{
    public class Explorer : Sprite, ICollector, IFightable, DogDemo.Common.IDrawable
    {
        private static float speed = 90f;
        private Rectangle scrollArea = new Rectangle(150, 100, 500, 400);

        #region Initialization
        public Explorer(Texture2D texture, Rectangle initialFrame, int frameCount, Vector2 worldLocation) : base(worldLocation, texture, initialFrame, Vector2.Zero)
        {
            int frameWidth = initialFrame.Width;
            int frameHeight = initialFrame.Height;
            //playerSprite = new Sprite(worldLocation, texture, initialFrame, Vector2.Zero);
            this.BoundingXPadding = 4;
            this.BoundingYPadding = 4;
            this.AnimateWhenStopped = false;
            CollectedItems = new List<string>();

            for (int x = 1; x < frameCount; x++)
            {
                this.AddFrame(new Rectangle(initialFrame.X + (frameHeight * x),
                    initialFrame.Y, frameWidth, frameHeight));
            }
        }
        #endregion
        #region Update and Draw

        public void DoUpdate(GameTime gameTime, ref TileMap tileMap)
        {
            handleInput(gameTime, ref tileMap);
            this.Update(gameTime);
            clampToWorld();
        }

        #endregion
        #region Input handling

        private Vector2 handleKeyboardMovement(KeyboardState keyState)
        {
            Vector2 keyMovement = Vector2.Zero;
            if (keyState.IsKeyDown(Keys.W))
            {
                keyMovement.Y--;
            }
            if (keyState.IsKeyDown(Keys.A))
            {
                keyMovement.X--;
            }
            if (keyState.IsKeyDown(Keys.S))
            {
                keyMovement.Y++;
            }
            if (keyState.IsKeyDown(Keys.D))
            {
                keyMovement.X++;
            }

            return keyMovement;
        }

        // TODO: add support for gamepad/configurable input

        private void handleInput(GameTime gameTime, ref TileMap tileMap)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            Vector2 moveAngle = Vector2.Zero;
            moveAngle += handleKeyboardMovement(Keyboard.GetState());

            if (moveAngle != Vector2.Zero)
            {
                moveAngle.Normalize();
                moveAngle = checkTileObstacles(elapsed, moveAngle, ref tileMap);
            }

            this.RotateTo(moveAngle);
            this.Velocity = moveAngle * speed;
            repositionCamera(gameTime, moveAngle);
        }

        #endregion
        #region Movement Limitations
        private void clampToWorld()
        {
            float CurrentX = this.WorldLocation.X;
            float CurrentY = this.WorldLocation.Y;

            CurrentX = MathHelper.Clamp(CurrentX, 0, Camera.WorldRectangle.Right - this.FrameWidth);
            CurrentY = MathHelper.Clamp(CurrentY, 0, Camera.WorldRectangle.Bottom - this.FrameHeight);

            this.WorldLocation = new Vector2(CurrentX, CurrentY);
        }

        private void repositionCamera(GameTime gameTime, Vector2 moveAngle)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            float moveScale = speed * elapsed;
            if ((this.ScreenRectangle.X < scrollArea.X) && (moveAngle.X < 0))
            {
                Camera.Move(new Vector2(moveAngle.X, 0) * moveScale);
            }
            if ((this.ScreenRectangle.Right > scrollArea.Right) && (moveAngle.X > 0))
            {
                Camera.Move(new Vector2(moveAngle.X, 0) * moveScale);
            }
            if ((this.ScreenRectangle.Y < scrollArea.Y) && (moveAngle.Y < 0))
            {
                Camera.Move(new Vector2(0, moveAngle.Y) * moveScale);
            }
            if ((this.ScreenRectangle.Bottom > scrollArea.Bottom) && (moveAngle.Y > 0))
            {
                Camera.Move(new Vector2(0, moveAngle.Y) * moveScale);
            }
        }

        private Vector2 checkTileObstacles(float elapsedTime, Vector2 moveAngle, ref TileMap tileMap)
        {
            Vector2 newHorizontalLocation = this.WorldLocation + (new Vector2(moveAngle.X, 0) * (speed * elapsedTime));
            Vector2 newVerticalLocation = this.WorldLocation + (new Vector2(0, moveAngle.Y) * (speed * elapsedTime));
            Rectangle newhorizontalRect = new Rectangle((int)newHorizontalLocation.X, (int)this.WorldLocation.Y, this.FrameWidth, this.FrameHeight);
            Rectangle newVerticalRect = new Rectangle((int)this.WorldLocation.X, (int)newVerticalLocation.Y, this.FrameWidth, this.FrameHeight);
            int horizLeftPixel = 0;
            int horizRightPixel = 0;
            int vertTopPixel = 0;
            int vertBottomPixel = 0;

            if (moveAngle.X < 0)
            {
                horizLeftPixel = (int)newhorizontalRect.Left;
                horizRightPixel = (int)this.WorldRectangle.Left;
            }
            if (moveAngle.X > 0)
            {
                horizLeftPixel = (int)this.WorldRectangle.Right;
                horizRightPixel = (int)newhorizontalRect.Right;
            }
            if (moveAngle.Y < 0)
            {
                vertTopPixel = (int)newVerticalRect.Top;
                vertBottomPixel = (int)this.WorldRectangle.Top;
            }
            if (moveAngle.Y > 0)
            {
                vertTopPixel = (int)this.WorldRectangle.Bottom;
                vertBottomPixel = (int)newVerticalRect.Bottom;
            }
            if (moveAngle.X != 0)
            {
                for (int x = horizLeftPixel; x < horizRightPixel; x++)
                {
                    for (int y = 0; y < this.FrameHeight; y++)
                    {
                        if (tileMap.IsWallTileByPixel(new Vector2(x, newHorizontalLocation.Y + y)))
                        {
                            moveAngle.X = 0;
                            break;
                        }
                    }
                    if (moveAngle.X == 0)
                    {
                        break;
                    }
                }
            }

            if (moveAngle.Y != 0)
            {
                for (int y = vertTopPixel; y < vertBottomPixel; y++)
                {
                    for (int x = 0; x < this.FrameWidth; x++)
                    {
                        if (tileMap.IsWallTileByPixel(new Vector2(newVerticalLocation.X + x, y)))
                        {
                            moveAngle.Y = 0;
                            break;
                        }
                    }

                    if (moveAngle.Y == 0)
                    {
                        break;
                    }
                }
            }

            return moveAngle;
        }
        #endregion

        #region ICollector

        private List<string> _collectedItems;
        public List<string> CollectedItems
        {
            get
            {
                return _collectedItems;
            }
            set
            {
                _collectedItems = value;
            }
        }

        public void DoCollect(ICollectable collectable)
        {
            CollectedItems.Add(collectable.ItemName);
        }

        #endregion
        private int _hp;
        public int HP
        {
            get
            {
                return _hp;
            }
            set
            {
                _hp = value;
            }
        }
    }
}
